package sanshui.system.trade.factory.trade.strategy;

import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sanshui.system.trade.db.entity.TradeAccountTbl;
import sanshui.system.trade.factory.data.Bar;
import sanshui.system.trade.factory.data.DataCache;
import sanshui.system.trade.factory.trade.TradeFee;
import sanshui.system.trade.factory.trade.TradeSystemContext;
import sanshui.system.trade.factory.trade.indicator.IndicatorCode;
import sanshui.system.trade.factory.trade.indicator.IndicatorResult;
import sanshui.system.trade.factory.trade.riskCtr.RiskCtrCode;
import sanshui.system.trade.factory.trade.worker.AbstractTradeWorker;
import sanshui.system.trade.model.TradeAccountModel;
import sanshui.system.trade.model.TradeHisPositionModel;
import sanshui.system.trade.util.IndicatorUtil;
import sanshui.system.trade.util.TradeFeeUtil;

import java.math.BigDecimal;
import java.util.*;

/**
 * 控制买卖数量
 *
 * */
public abstract class AbstractStrategy implements TradeStrategy {
    private static final Logger logger = LoggerFactory.getLogger(AbstractStrategy.class);

    private int hisDataNum = 60;
    private int hisDataMin = 5;

    protected StrategyCode strategyCode;


    @Override
    public abstract StrategyCode getStrategyCode();

    @Override
    public IndicatorResult exec(Bar bar, TradeSystemContext tradeSystemContext) {
        IndicatorResult indicatorResult = new IndicatorResult();
        indicatorResult.setCode(bar.getSymbol());

        DataCache dataCache = tradeSystemContext.getDataCache();

        Map<String, List<Bar>> hisDataMap = dataCache.getHisPriceDataMap();
        List<Bar> hisDataList = hisDataMap.getOrDefault(bar.getSymbol(), new ArrayList<>());
        this.addHisValue(bar, hisDataList);
        hisDataMap.put(bar.getSymbol(), hisDataList);
        // 如果历史数据没有超过一定数量，是不会进行计算的
        if (!this.isOverHis(hisDataMin, hisDataList)){
            return indicatorResult;
        }
        // 计算交易策略、风控策略默认指标
        StrategyCode strategyCode = tradeSystemContext.getStrategy().getStrategyCode();
        List<IndicatorCode> allIndicatorCode = new ArrayList<>();
        List<IndicatorCode> strategyIndicators = strategyCode.getIndicatorCodes();
        List<IndicatorCode> riskCtrIndicators = tradeSystemContext.getRiskStrategy().getRiskName().getIndicatorCodes();
        allIndicatorCode.addAll(strategyIndicators);
        allIndicatorCode.addAll(riskCtrIndicators);

        // 数据缓存器
        IndicatorResult defaultInRe = this.autoComputeStrategyIndicates(bar, dataCache, allIndicatorCode);
        // 策略自定义指标
        IndicatorResult exec = this.execCustom(bar, tradeSystemContext);
        // 合并两个Map，以exec为准，为其补充指标
        exec.setCurrentBar(bar);
        exec.setIndicatorCodes(allIndicatorCode);
        exec.setParamMap(this.mergeMap(defaultInRe.getParamMap(), exec.getParamMap()));
        return exec;
    }

    protected IndicatorResult execCustom(Bar bar, TradeSystemContext tradeSystemContext){
        return new IndicatorResult();
    }

    public abstract StrategyResult exec(String code, IndicatorResult indicatorResult, TradeSystemContext tradeSystemContext);

    @Override
    public void updateEnd(TradeSystemContext tradeSystemContext) {

    }

    protected void addHisValue(Long value, List<Long> his){
        if (his.size() > this.hisDataNum){
            his.remove(0);
        }
        his.add(value);
    }

    protected void addHisValue(Bar value, List<Bar> his){
        if (his.size() > this.hisDataNum){
            his.remove(0);
        }
        his.add(value);
    }

    private boolean isOverHis(int overNumLimit, List<Bar> his){
        return his.size() >= overNumLimit;
    }

    private IndicatorResult autoComputeStrategyIndicates(Bar bar, DataCache dataCache, List<IndicatorCode> indicatorCodes){
        IndicatorResult result = new IndicatorResult();
        Map<String, List<String>> indicatorsMap = dataCache.getIndicatorsMap();
        Map<String, List<Bar>> hisPriceDataMap = dataCache.getHisPriceDataMap();
        String code = bar.getSymbol();
        List<Bar> hisBarList = hisPriceDataMap.get(code);
        for (IndicatorCode indicatorCode : indicatorCodes) {
            IndicatorCode.Type type = indicatorCode.getName();
            String key = indicatorCode.key();
            switch (type){
                case M_N:
                    List<Long> mn = IndicatorUtil.MAn(
                            hisPriceDataMap.get(code),
                            indicatorCode.getRate());
                    indicatorsMap.put(key, IndicatorUtil.parseLong2Str(mn));
                    break;
                case TR: // 瞬时值
                    Long tr = IndicatorUtil.calculateTR(
                            hisBarList.get(hisBarList.size()-2),
                            hisBarList.get(hisBarList.size()-1));
                    indicatorsMap.put(key, Collections.singletonList(tr.toString()));
                    break;
                case ATR:
                    List<Long> atrList = IndicatorUtil.calculateATRList(
                            indicatorCode.getRate(),
                            IndicatorUtil.parseBar2LongClose(hisBarList));
                    indicatorsMap.put(key, IndicatorUtil.parseLong2Str(atrList));
                    break;

            }
        }
        result.setCode(code);
        result.setCurrentBar(bar);
        result.setParamMap(indicatorsMap);
        return result;
    }

    private Map<String, List<String>> mergeMap(Map<String, List<String>> byDefault, Map<String, List<String>> byCumtom){
        for (String indicatorKeyDefault : byDefault.keySet()) {
            if (!byCumtom.containsKey(indicatorKeyDefault)){
                byCumtom.put(indicatorKeyDefault, byDefault.get(indicatorKeyDefault));
            }
        }
        return byCumtom;
    }
}
